// WebGrab.cpp: implementation of the CWebGrab class.
//
//////////////////////////////////////////////////////////////////////

#include "stdafx.h"
#include "tinypp.h"
#include "WebGrab.h"

#ifdef _DEBUG
#undef THIS_FILE
static char THIS_FILE[]=__FILE__;
#define new DEBUG_NEW
#endif


#define BUFFER_SIZE 4095

/////////////////////////////////////////////////////////////////////////////
// CWebGrab

CWebGrab::CWebGrab()
{
	m_pSession = NULL;
	m_timeOut = 500; // .5 seconds by default
	m_useProxy = false;
	m_infoStatusCode=0;
}

CWebGrab::~CWebGrab()
{
    Close();
}

BOOL CWebGrab::Initialise(LPCTSTR szAgentName /*=NULL*/)
{
    Close();
	m_infoStatusCode=0;
    m_pSession = new CWebGrabSession(szAgentName);

	if (m_timeOut != 0)
		m_pSession->SetOption(INTERNET_OPTION_DATA_RECEIVE_TIMEOUT, m_timeOut);

	// added Bryce
	if (m_useProxy)
	{
		char buf[10];
		itoa(m_Port,buf,10);
		CString temp = m_Proxy+":"+(CString)buf;
		INTERNET_PROXY_INFO proxyinfo;
		proxyinfo.dwAccessType = INTERNET_OPEN_TYPE_PROXY;
		proxyinfo.lpszProxy = temp;
		proxyinfo.lpszProxyBypass = NULL;
		m_pSession->SetOption(INTERNET_OPTION_PROXY, (LPVOID)&proxyinfo, sizeof(INTERNET_PROXY_INFO));
	}
	
	return (m_pSession != NULL);
}

void CWebGrab::Close()
{
    if (m_pSession)
    {
        m_pSession->Close();
        delete m_pSession;
    }
    m_pSession = NULL;
}

CString CWebGrab::GetErrorMessage()
{
	return m_pSession->GetErrorMessage();
}

void CWebGrab::SetTimeOut(DWORD timeOut)
{
	m_timeOut = timeOut;
}

double CWebGrab::GetRate()
{
	return m_transferRate;
}

void CWebGrab::SetProxyServer(LPCSTR server)
{
	m_Proxy = server;
}

void CWebGrab::SetProxyPort(UINT port)
{
	m_Port = port;
}

void CWebGrab::SetUseProxy(bool use)
{
	m_useProxy = use;
}

void CWebGrab::SetProxy(LPCSTR proxy, WORD port, bool useProxy )
{
	SetProxyServer(proxy);
	SetProxyPort(port);
	SetUseProxy(useProxy);
}

SHORT CWebGrab::GetErrorCode()
{
	return (!m_ErrorMessage.IsEmpty()); //just for now say...
}

BOOL CWebGrab::GetFile(LPCTSTR szURL, LPCTSTR szFileName, LPCTSTR szAgentName /*=NULL*/)
{
  //  TRACE1("URL is %s\n", szURL);
	m_rawHeaders ="";
	m_infoStatusCode=0;

    if (!m_pSession && !Initialise(szAgentName))
        return FALSE;

    DWORD dwCount = 0;
    CHttpFile* pFile = (CHttpFile*) m_pSession->OpenURL(szURL, 1,
			INTERNET_FLAG_TRANSFER_BINARY 
			//| INTERNET_OPEN_FLAG_USE_EXISTING_CONNECT |
			//| INTERNET_FLAG_DONT_CACHE
			//| INTERNET_FLAG_RELOAD
			);
	if(!pFile)
		return FALSE;
    
	FILE* fp=fopen(szFileName,"wb");
	if(!fp)
		return false;

    COleDateTime startTime = COleDateTime::GetCurrentTime();
	
	BYTE buffer[BUFFER_SIZE+1];
	try {
		UINT nRead = 0;
		dwCount = 0;
		do
		{
			nRead = pFile->Read(buffer, BUFFER_SIZE);
			if (nRead > 0)
			{
				buffer[nRead] = 0;                    
				fwrite(buffer,1,nRead,fp);
				dwCount += nRead;                
				COleDateTimeSpan elapsed = COleDateTime::GetCurrentTime() - startTime;
				double dSecs = elapsed.GetTotalSeconds();
				if (dSecs > 0.0){
					m_transferRate = (double)dwCount / 1024.0 / dSecs;
					m_pSession->SetStatus("Read %d bytes (%0.1f Kb/s)", 
						dwCount, m_transferRate );
					
				}else{
					m_pSession->SetStatus("Read %d bytes", dwCount);
					m_transferRate = dwCount;
				}
			}
		}
		while (nRead > 0);
	}
	catch (CFileException *e)
	{
		TCHAR   szCause[255];
		e->GetErrorMessage(szCause, 255);
		m_ErrorMessage = szCause;
		m_pSession->SetStatus(szCause);
		//e->ReportError();
		e->Delete();
		delete pFile;
		fclose(fp);
		return FALSE;
	}
	pFile->QueryInfoStatusCode(m_infoStatusCode);       
	pFile->QueryInfo(HTTP_QUERY_RAW_HEADERS ,m_rawHeaders);
	pFile->Close();
	delete pFile;
    
    m_pSession->SetStatus("");
	fclose(fp);
    return TRUE;
}

DWORD CWebGrab::GetPageStatusCode()
{
	return m_infoStatusCode;
}

CString CWebGrab::GetRawHeaders()
{
	return m_rawHeaders;
}



/////////////////////////////////////////////////////////////////////////////
// CWebGrabSession member functions

CWebGrabSession::CWebGrabSession(LPCTSTR szAgentName) 
                : CInternetSession(szAgentName) // , 1, INTERNET_OPEN_TYPE_PRECONFIG, 
{
    CommonConstruct();
}

CWebGrabSession::~CWebGrabSession()
{
}

void CWebGrabSession::CommonConstruct() 
{
    try {
        EnableStatusCallback(TRUE);
    }
    catch (...)
    {}
}


void CWebGrabSession::OnStatusCallback(DWORD dwContext, 
                                       DWORD dwInternetStatus, 
                                       LPVOID lpvStatusInformation, 
                                       DWORD dwStatusInformationLength)
{
	UNUSED_ALWAYS(dwContext);

    // Status callbacks need thread-state protection. 
    AFX_MANAGE_STATE( AfxGetAppModuleState( ) );

    CString str;

	//TRACE1("Internet context=%d: %d\n", dwContext);

	switch (dwInternetStatus)
	{
	case INTERNET_STATUS_RESOLVING_NAME:
		str.Format("Resolving name for %s", lpvStatusInformation);
		break;

	case INTERNET_STATUS_NAME_RESOLVED:
		str.Format("Resolved name for %s", lpvStatusInformation);
		break;

	case INTERNET_STATUS_HANDLE_CREATED:
		//str.Format("Handle %8.8X created", hInternet);
		break;

	case INTERNET_STATUS_CONNECTING_TO_SERVER:
		{
		//sockaddr* pSockAddr = (sockaddr*) lpvStatusInformation;
		str.Format("Connecting to socket address "); //, pSockAddr->sa_data);
		}
		break;

	case INTERNET_STATUS_REQUEST_SENT:
		str.Format("Request sent");
		break;

	case INTERNET_STATUS_SENDING_REQUEST:
		str.Format("Sending request...");
		break;

	case INTERNET_STATUS_CONNECTED_TO_SERVER:
		str.Format("Connected to socket address");
		break;

	case INTERNET_STATUS_RECEIVING_RESPONSE:
        return;
		str.Format("Receiving response...");
		break;

	case INTERNET_STATUS_RESPONSE_RECEIVED:
		str.Format("Response received");
		break;

	case INTERNET_STATUS_CLOSING_CONNECTION:
		str.Format("Closing the connection to the server");
		break;

	case INTERNET_STATUS_CONNECTION_CLOSED:
		str.Format("Connection to the server closed");
		break;

	case INTERNET_STATUS_HANDLE_CLOSING:
        return;
		str.Format("Handle closed");
		break;

	case INTERNET_STATUS_REQUEST_COMPLETE:
        // See the CInternetSession constructor for details on INTERNET_FLAG_ASYNC.
        // The lpvStatusInformation parameter points at an INTERNET_ASYNC_RESULT 
        // structure, and dwStatusInformationLength contains the final completion 
        // status of the asynchronous function. If this is ERROR_INTERNET_EXTENDED_ERROR, 
        // the application can retrieve the server error information by using the 
        // Win32 function InternetGetLastResponseInfo. See the ActiveX SDK for more 
        // information about this function. 
		if (dwStatusInformationLength == sizeof(INTERNET_ASYNC_RESULT))
		{
			INTERNET_ASYNC_RESULT* pResult = (INTERNET_ASYNC_RESULT*) lpvStatusInformation;
			str.Format("Request complete, dwResult = %8.8X, dwError = %8.8X",
				        pResult->dwResult, pResult->dwError);
		}
		else
			str.Format("Request complete");
		break;

	case INTERNET_STATUS_CTL_RESPONSE_RECEIVED:
	case INTERNET_STATUS_REDIRECT:
	default:
		str.Format("Unknown status: %d", dwInternetStatus);
		break;
	}

    SetStatus(str);

    TRACE("CWebGrabSession::OnStatusCallback: %s\n",str);
}

void CWebGrabSession::SetStatus(LPCTSTR fmt, ...)
{
    va_list args;
    TCHAR buffer[512];

    va_start(args, fmt);
    _vstprintf(buffer, fmt, args);
    va_end(args);

    TRACE1("CWebGrabSession::SetStatus: %s\n", buffer);
	errorMessage = (CString) buffer;
}

CString CWebGrabSession::GetErrorMessage()
{
	return errorMessage;
}
